home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir31 / in_out.zip / PORT-IN.OUT < prev   
Text File  |  1993-01-16  |  15KB  |  347 lines

  1. ╔════════════════════════════════════════════════════════════════════════════╗
  2. ║          The - INs ORs ANDs OUTs - of creating sound on the IBM PC         ║
  3. ║                                                                            ║
  4. ║        by  William Cravener  520 N. Stateline Rd.  Sharon, Pa. 16146       ║
  5. ║                                                                            ║
  6. ║         »-Swift-Ware->      Copyright 1991-93       CIS: 72230,1306        ║
  7. ╚════════════════════════════════════════════════════════════════════════════╝
  8.  
  9.         There are two important electronic chips involved in creating sound 
  10. on the IBM PC - the 8253 timer chip (channel 2 of this chip is connected to 
  11. the speaker),  and the 8255 peripheral interface chip  (it appears regardless
  12. of what peripheral interface chip is used in any particular machine, the same
  13. port address and bit assignments are used).  The pulse rate of each chip can
  14. be altered,  and by combining the actions of the two chips it is possible to
  15. produce special sound effects.
  16.  
  17.         To make sounds on the IBM PC you must actually turn ON and OFF an
  18. electronic "gate" (which is a kind of toggle switch).  Each time we toggle the 
  19. "gate" ON and OFF again, we create a pulse: a brief period when current flows 
  20. in a circuit (look at the example below).  These pulses are amplified and sent 
  21. to the speaker, where they make a sound.  This "gate" is turned ON and OFF 
  22. with the assembly OUT instruction.
  23.  
  24.  
  25.          One
  26.         Pulse
  27.        |     |
  28.  +     ┌─────┐     ┌─────┐     ┌─────┐
  29.        │     │     │     │     │     │
  30.  0 ────┘     └─────┘     └─────┘     └────  <-- Wave form sent to the Speaker.
  31.        |     |
  32.        |   "gate"
  33.        |    is turned OFF here
  34.      "gate"
  35.       is turned ON here
  36.  
  37.  
  38.         The faster we send the pulses, the higher the pitch of the sound. We 
  39. can control how fast we send the pulses by putting a delay loop into our
  40. program.  We then turn the "gate" ON, delay, turn the "gate" OFF, delay, and 
  41. so on and so on. The assembly LOOP instruction is used to cause the delay that
  42. we will need for our example sound program.
  43.  
  44.         But, before we go on to the example program lets talk a little about 
  45. addressing the PORTs (I/O Ports).  Ports are something like registers, in
  46. that you can send 8-bit or 16-bit data to them. This is always accomplished
  47. using the AL or AX register, you can also read the port contents back into 
  48. the AL or AX register. The big difference between ports and registers is that
  49. ports can be connected to devices either inside or outside of your computer.
  50.  
  51.         How then, do you access these I/O Ports???    Well, its not that 
  52. difficult once you acquire a little understanding about how to send information 
  53. to these ports using a few very simple assembly language instructions.
  54.  
  55.         The two most important instructions you will be using are the assembly
  56. IN and OUT instructions. The IN instruction places a byte of information into
  57. the AL or AX register, the OUT instruction copies a byte or word of information
  58. from the AL or AX register. 
  59.  
  60. The instruction that turns our "gate" ON and OFF is:
  61.  
  62.  
  63. OUT     61H, AL    
  64.  
  65.  
  66. This instruction copies the contents of the AL register to the port 61H.
  67.  
  68.         This port addresses the 8255 or equivalent programmable peripheral
  69. interface chip or PPI.  The PPI is used to control the keyboard, the speaker
  70. and the computer configuration settings.
  71.  
  72.         OUT is very much like the assembly MOV instruction, but instead of
  73. moving information to a register we copy it from a register to a port address
  74. as in the above example (port address 61H).
  75.  
  76.         Now in the case of creating sound we need to be concerned with two of
  77. the 8-bits we send to port address 61H.  These are the bits numbered 0 and 1.
  78.  
  79.                8-bit number -->  11111111
  80. The two we are interested in ->  111111XX
  81. (marked as X's)                        ||___ bit number 0
  82.                                        |____ bit number 1
  83.  
  84.         In order to change bits 0 and 1 (without changing the other 6 bits),
  85. we need to find out how all the bits are initially set.  This is easily done 
  86. by using the assembly IN instruction to retreive this value. Once we know how
  87. all 8-bits are initially set, we can change the first two (0 and 1) then copy
  88. the value back to the port address 61H.
  89.  
  90.  
  91. IN      AL, 61H    
  92.  
  93.  
  94. This instruction copies the current 8-bit value of port 61H to the AL register.
  95.  
  96.         Once we have this 8-bit value we need to change bits 0 and 1 so we
  97. can send the changed ON or OFF value back OUT to our port address.  This is a
  98. two part procedure, first we wish to turn the speaker ON so we OR the 8-bit
  99. value with a value of our own that will not change the upper 6-bits, the 
  100. assembly OR instruction accomplishes this:
  101.  
  102.  
  103. OR      AL, 00000011B    ;<- More often then not programmers show 
  104.                     |    ;   this OR or AND value as a binary number.
  105.                     |
  106.                     |____ The letter "B" simply tells the assembler
  107.                           that this group of numbers is a binary value.
  108.  
  109.  
  110. The unknown value we get from port 61H ---> 101010 00 <- ( IN  AL, 61H )
  111.  
  112. Then we first OR it with this value ------> 000000 11 <-Our ORing ON value -
  113.                                                         this value will enable
  114.                                                         the speaker.
  115.  
  116. Leaves all bits except 0 and 1 unchanged -> 101010 11 <-The resulting value -
  117.                                                    ||   bits 0 and 1 have both
  118.                                             bit 1__||   been forced to values
  119.                                             bit 0___|   of - 1  (ON)
  120.  
  121.  
  122.         Now we want to return this altered number back OUT to port 61H to 
  123. turn ON the speaker. This is easily accomplished by using the above explained
  124. assembly OUT instruction in the following manner.
  125.  
  126.  
  127. OUT     61H, AL    ;<-- copy the value in the AL register to Port 61H
  128.  
  129.  
  130.         At this point the computers speaker will sound until a new binary 
  131. value is sent back OUT to port 61H to turn the speaker OFF.
  132.  
  133. Here is the complete code to turn ON the speaker:
  134.  
  135.  
  136. IN      AL, 61H          ;Get current value of port 61H.
  137. OR      AL, 00000011B    ;OR AL to this value, forcing first two bits high.
  138. OUT     61H, AL          ;Copy it to port 61H of the PPI chip.
  139.  
  140.  
  141.         Here is where our next assembly instruction needs to enter the picture
  142. to turn the speaker OFF. That instruction is the AND instruction, kind of like
  143. the opposite of the OR instruction. As with turning ON the speaker we must use
  144. a similar procedure to turn the speaker OFF.
  145.  
  146. First get unknown value from port 61H ----> 101010 11 <- ( IN  AL, 61H )
  147.  
  148. Then we first AND it with this value -----> 111111 00 <-Our ANDing OFF value -
  149. (This 8-bit number is the exact opposite                this value will disable
  150. of our OR value above).                                 the speaker.
  151.  
  152. Leaves all bits except 0 and 1 unchanged -> 101010 00 <-The resulting value -
  153.                                                    ||   bits 0 and 1 have both
  154.                                             bit 1__||   been forced to values
  155.                                             bit 0___|   of - 0  (OFF)
  156.  
  157. Here is the complete code to turn OFF the speaker:
  158.  
  159.  
  160. IN      AL,61H          ;Get current value of port 61H.
  161. AND     AL,11111100B    ;AND AL to this value, forcing first two bits low.
  162. OUT     61H,AL          ;Copy it to port 61H of the PPI chip.
  163.  
  164.  
  165. Ok, now if you think about it if we were to turn the speaker ON with:
  166.  
  167. IN      AL, 61H
  168. OR      AL, 00000011B
  169. OUT     61H, AL
  170.  
  171. And then, directly turn the speaker back OFF with:
  172.  
  173. IN      AL, 61H
  174. AND     AL, 11111100B
  175. OUT     61H, AL
  176.  
  177.         You wouldn't hear a thing (except maybe a click), it all happens to
  178. fast.  We need to cause some kind of delay between the two procedures. We do
  179. this by setting up a LOOP instruction between our two procedures.  This is
  180. done by putting a value in the CX register and executing the assembly LOOP 
  181. instruction.
  182.  
  183. Here is an example of its use:
  184.  
  185. MOV     CX, 100          ;Repeat the loop 100 times
  186. DELAY_LOOP:              ;We loop back to here
  187. LOOP    DELAY_LOOP       ;Jump repeatedly to DELAY_LOOP until CX = 0
  188.  
  189. This will sound the speaker for a Duration of 100 repeated Loops.
  190.  
  191. Here is the Whole Noisy Routine:
  192.  
  193.  
  194. IN      AL,61H          ;Get current value of port 61H.
  195. OR      AL,00000011B    ;OR AL to this value, forcing first two bits high.
  196. OUT     61H,AL          ;Copy it to port 61H of the PPI chip.
  197.  
  198. MOV     CX,100          ;Repeat the loop 100 times
  199. DELAY_LOOP:             ;We loop back to here
  200. LOOP    DELAY_LOOP      ;Jump repeatedly to DELAY_LOOP until CX = 0
  201.  
  202. IN      AL,61H          ;Get current value of port 61H.
  203. AND     AL,11111100B    ;AND AL to this value, forcing first two bits low.
  204. OUT     61H,AL          ;Copy it to port 61H of the PPI chip.
  205.  
  206.  
  207.         This is a very good method of creating beeps and boops, but we what 
  208. to get a little more involved then this and create more interesting sound
  209. effects. We could create many different sounds if we were to include help
  210. from the computers timer chip. This is the 8253 programmable timer and has
  211. the ability to enable a certain action at a certain point in time. It senses 
  212. timing from oscillations it recieves from the PC's 8284 oscillator chip, which
  213. generates 1,193,180 pulses per second.  The 8253 chip can then be instructed 
  214. how many of these pulses it should wait for before triggering a certain action.
  215. In the case of tone generation, this action consists of sending a pulse to the
  216. speaker.  Before executing this action, the 8253 chip must be programmed for a
  217. particular frequency it should generate.
  218.  
  219.         There are actually three different timers built into the computer.
  220. Timer 0 is used in DMA data transfer (Direct Memory Access), Timer 1 is used
  221. as a system clock oscillator (18.2 times per second), and the one we are
  222. interested in Timer 2 which is connected to the computers speaker.
  223.  
  224.         Using the Timer to generate sound is a little more complicated than 
  225. simply sending pulses to the speaker. There are three steps envolved in using
  226. this method of sound creation. 
  227.     
  228.     Step 1.  Copy a certain number to Timer 2 to initialize it.
  229.     Step 2.  Copy a 16 bit number to Timer 2 to establish the frequency 
  230.              of the tone to be generated.
  231.     Step 3.  Turn on the speaker to enable the frequency adjusted sound
  232.              to be heard.
  233.  
  234.         You access Timer 2 thru two port addresses,  the first is used to 
  235. initialize (make it ready to receive data) thru port 43H, you then send a 
  236. 16-bit value in two 8-bit steps.  First, the Least Significant Byte (LSB)
  237. is copied to port address 42H, second, the Most Significant Byte (MSB) is
  238. copied to port address 42H. A 16-bit value is called a WORD, a WORD value
  239. is made up of two BYTES, LSB and MSB.
  240.  
  241.                          _______________ ____ (WORD)
  242.                         |               |
  243. 16-bit binary value ->  00000000 00000001
  244.                         |      | |______|____ (BYTE) LSB
  245.                         |      |         
  246.                         |______|_____________ (BYTE) MSB
  247.  
  248.  
  249. Here is how all this is accomplished:
  250.  
  251. MOV     BX, 1            ; Frequency Value.
  252.                          ; Formula = 1,193,180 \ frequency value
  253.                          ; Will put it in BX for now. 
  254.                          ; The lower the value the higher
  255.                          ; the sound / the higher the value
  256.                          ; the lower the sound.
  257.  
  258. MOV     AL, 10110110B    ; The Magic Number (use this binary number only!)
  259. OUT     43H, AL          ; Send it to the initializing port 43H Timer 2.
  260.  
  261. MOV     AX, BX           ; Move our Frequency Value into AX.
  262.  
  263. OUT     42H, AL          ; Send LSB to port 42H.
  264. MOV     AL, AH           ; Move MSB into AL
  265. OUT     42H, AL          ; Send MSB to port 42H.
  266.  
  267.  
  268. IN      AL, 61H          ; Get current value of port 61H.
  269. OR      AL, 00000011B    ; OR AL to this value, forcing first two bits high.
  270. OUT     61H, AL          ; Copy it to port 61H of the PPI Chip
  271.                          ; to turn ON the speaker.
  272.  
  273. MOV     CX, 100          ; Repeat the loop 100 times.
  274. DELAY_LOOP:              ; We loop back to here.
  275. LOOP    DELAY_LOOP       ; Jump repeatedly to DELAY_LOOP until CX = 0
  276.  
  277. IN      AL, 61H          ; Get current value of port 61H.
  278. AND     AL, 11111100B    ; AND AL to this value, forcing first two bits low.
  279. OUT     61H, AL          ; Copy it to port 61H of the PPI Chip
  280.                          ; to turn OFF the speaker.
  281.  
  282.  
  283.         Next we need to make our sound maker more interesting. To do this 
  284. we will simply use a method of repeating the whole thing a specified number
  285. of times and also increment the frequency value to create a sound that drops
  286. in frequency. To accomplish this we will use the assembly JMP instruction 
  287. and also at the same time, increment our frequency value.
  288.  
  289. Here is a complete example:
  290.  
  291.  
  292. MOV     DX,2000          ; Number of times to repeat whole routine.
  293.  
  294. MOV     BX,1             ; Frequency value.
  295.  
  296. MOV     AL, 10110110B    ; The Magic Number (use this binary number only)
  297. OUT     43H, AL          ; Send it to the initializing port 43H Timer 2.
  298.  
  299. NEXT_FREQUENCY:          ; This is were we will jump back to 2000 times.
  300.  
  301. MOV     AX, BX           ; Move our Frequency value into AX.
  302.  
  303. OUT     42H, AL          ; Send LSB to port 42H.
  304. MOV     AL, AH           ; Move MSB into AL  
  305. OUT     42H, AL          ; Send MSB to port 42H.
  306.  
  307. IN      AL, 61H          ; Get current value of port 61H.
  308. OR      AL, 00000011B    ; OR AL to this value, forcing first two bits high.
  309. OUT     61H, AL          ; Copy it to port 61H of the PPI Chip
  310.                          ; to turn ON the speaker.
  311.  
  312. MOV     CX, 100          ; Repeat loop 100 times
  313. DELAY_LOOP:              ; Here is where we loop back too.
  314. LOOP    DELAY_LOOP       ; Jump repeatedly to DELAY_LOOP until CX = 0
  315.  
  316.  
  317. INC     BX               ; Incrementing the value of BX lowers 
  318.                          ; the frequency each time we repeat the
  319.                          ; whole routine
  320.  
  321. DEC     DX               ; Decrement repeat routine count
  322.  
  323. CMP     DX, 0            ; Is DX (repeat count) = to 0
  324. JNZ     NEXT_FREQUENCY   ; If not jump to NEXT_FREQUENCY
  325.                          ; and do whole routine again.
  326.  
  327.                          ; Else DX = 0 time to turn speaker OFF
  328.  
  329. IN      AL,61H           ; Get current value of port 61H.
  330. AND     AL,11111100B     ; AND AL to this value, forcing first two bits low.
  331. OUT     61H,AL           ; Copy it to port 61H of the PPI Chip
  332.                          ; to turn OFF the speaker.
  333.  
  334.  
  335. In conclusion, with the included examples and a little imagination, there is no
  336. limit to the sound effects that are possible to create.
  337.  
  338. Included examples are:
  339.  
  340.         PHASOR.ASM
  341.         FONETONE.ASM
  342.  
  343. Have Fun !! 
  344.  
  345. ================================================================================
  346.  
  347.